<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Models\OperationLog;
use Illuminate\Support\Facades\Log;

class LogOperation
{
    /**
     * 不记录日志的路径
     *
     * @var array
     */
    protected $except = [
        'api/me',
        'api/online-users',
        'api/refresh',
    ];

    /**
     * 不记录日志的请求方法
     *
     * @var array
     */
    protected $exceptMethods = [
        'GET',
    ];

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        // 只记录成功的请求
        if ($this->shouldLog($request, $response)) {
            $this->logOperation($request, $response);
        }

        return $response;
    }

    /**
     * 判断是否应该记录日志
     *
     * @param Request $request
     * @param Response $response
     * @return bool
     */
    protected function shouldLog(Request $request, Response $response): bool
    {
        // 只记录成功的请求
        if ($response->getStatusCode() !== 200) {
            return false;
        }

        // 排除不记录日志的路径
        if (in_array($request->path(), $this->except)) {
            return false;
        }

        // 排除不记录日志的请求方法
        if (in_array($request->method(), $this->exceptMethods)) {
            return false;
        }

        // 必须有登录用户
        $user = auth()->user();
        if (!$user) {
            return false;
        }

        return true;
    }

    /**
     * 记录操作日志
     *
     * @param Request $request
     * @param Response $response
     * @return void
     */
    protected function logOperation(Request $request, Response $response): void
    {
        try {
            $user = auth()->user();
            
            // 获取响应数据（限制长度）
            $responseContent = $response->getContent();
            $responseData = null;
            $status = 'success';
            
            if ($responseContent) {
                $decoded = json_decode($responseContent, true);
                if ($decoded) {
                    $status = ($decoded['code'] ?? 200) === 200 ? 'success' : 'failed';
                    // 限制响应数据大小，避免日志过大
                    $responseData = json_encode($decoded, JSON_UNESCAPED_UNICODE);
                    if (strlen($responseData) > 2000) {
                        $responseData = substr($responseData, 0, 2000) . '...';
                    }
                }
            }

            // 根据请求路径和方法生成操作说明
            $description = $this->generateDescription($request);
            
            OperationLog::create([
                'user_id' => $user->id,
                'username' => $user->username,
                'method' => $request->method(),
                'path' => $request->path(),
                'description' => $description,
                'params' => $this->filterParams($request->all()),
                'ip' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'status' => $status,
                'message' => $responseData,
            ]);
        } catch (\Exception $e) {
            // 记录日志失败不应该影响请求
            Log::error('操作日志记录失败: ' . $e->getMessage());
        }
    }

    /**
     * 过滤敏感参数
     *
     * @param array $params
     * @return array
     */
    protected function filterParams(array $params): array
    {
        $sensitiveKeys = [
            'password',
            'password_confirmation',
            'old_password',
            'token',
            'api_token',
            'secret',
            'api_key',
            'access_token',
            'refresh_token',
            'private_key',
            'public_key',
        ];
        
        // 需要脱敏的字段
        $maskingService = app(\App\Services\DataMaskingService::class);
        
        foreach ($params as $key => $value) {
            // 过滤敏感键
            if (in_array(strtolower($key), array_map('strtolower', $sensitiveKeys))) {
                $params[$key] = '***';
                continue;
            }
            
            // 脱敏手机号
            if (stripos($key, 'phone') !== false && is_string($value)) {
                $params[$key] = $maskingService->maskPhone($value);
                continue;
            }
            
            // 脱敏邮箱
            if (stripos($key, 'email') !== false && is_string($value)) {
                $params[$key] = $maskingService->maskEmail($value);
                continue;
            }
            
            // 脱敏身份证
            if (stripos($key, 'id_card') !== false && is_string($value)) {
                $params[$key] = $maskingService->maskIdCard($value);
                continue;
            }
            
            // 处理嵌套数组
            if (is_array($value)) {
                $params[$key] = $this->filterParams($value);
            }
        }

        return $params;
    }

    /**
     * 根据请求路径和方法生成操作说明
     *
     * @param Request $request
     * @return string
     */
    protected function generateDescription(Request $request): string
    {
        $method = $request->method();
        $path = $request->path();
        
        // 移除 api/ 前缀
        $path = preg_replace('/^api\//', '', $path);
        
        // 解析路径，获取资源类型和操作
        $segments = explode('/', $path);
        
        // 资源类型映射
        $resourceMap = [
            'users' => '用户',
            'roles' => '角色',
            'menus' => '菜单',
            'permissions' => '权限',
            'departments' => '部门',
            'operation-logs' => '操作日志',
            'login-logs' => '登录日志',
            'online-users' => '在线用户',
            'storage-config' => '存储配置',
            'websocket-config' => 'WebSocket配置',
            'profile' => '个人资料',
        ];
        
        // HTTP 方法映射
        $actionMap = [
            'POST' => '创建',
            'PUT' => '更新',
            'PATCH' => '更新',
            'DELETE' => '删除',
        ];
        
        // 处理特殊路径（不需要资源名称的路径）
        if ($path === 'logout') {
            return '退出登录';
        }
        if ($path === 'login') {
            return '用户登录';
        }
        if ($path === 'forgot-password') {
            return '忘记密码';
        }
        if ($path === 'reset-password') {
            return '重置密码';
        }
        if ($path === 'refresh') {
            return '刷新Token';
        }
        
        // 特殊路径处理
        if (count($segments) >= 1) {
            $resource = $segments[0];
            $resourceName = $resourceMap[$resource] ?? $resource;
            
            // 检查是否是 export/list 路径（需要在检查资源ID之前）
            if (isset($segments[1]) && $segments[1] === 'export') {
                if (isset($segments[2]) && $segments[2] === 'list') {
                    return "导出{$resourceName}列表";
                }
                return "导出{$resourceName}";
            }
            
            // 检查是否是 import 路径
            if (isset($segments[1]) && $segments[1] === 'import') {
                return "导入{$resourceName}";
            }
            
            // 检查是否是其他特殊操作（三段路径：resource/id/action）
            if (count($segments) >= 3) {
                $action = $segments[2];
                
                // 批量操作
                if ($action === 'batch-destroy') {
                    return "批量删除{$resourceName}";
                }
                if ($action === 'batch-update-status') {
                    return "批量更新{$resourceName}状态";
                }
                if ($action === 'force-logout') {
                    return "强制{$resourceName}退出登录";
                }
                if ($action === 'password') {
                    return "修改{$resourceName}密码";
                }
                if ($action === 'avatar') {
                    return "上传{$resourceName}头像";
                }
                if ($action === 'clear') {
                    return "清空{$resourceName}";
                }
                if ($action === 'permissions') {
                    return "查看{$resourceName}权限";
                }
            }
            
            // 标准 RESTful 操作
            if (isset($actionMap[$method])) {
                $actionName = $actionMap[$method];
                
                // 如果有资源ID，说明是操作特定资源
                if (isset($segments[1]) && is_numeric($segments[1])) {
                    $resourceId = $segments[1];
                    return "{$actionName}{$resourceName} (ID: {$resourceId})";
                }
                
                // 如果没有资源ID，说明是创建操作
                if ($method === 'POST') {
                    return "创建{$resourceName}";
                }
            }
        }
        
        // 默认：根据方法生成描述
        $actionName = $actionMap[$method] ?? $method;
        $resourceName = isset($segments[0]) ? ($resourceMap[$segments[0]] ?? $segments[0]) : '';
        
        return $resourceName ? "{$actionName}{$resourceName}" : "{$method} {$path}";
    }
}

